let ws = require('nodejs-websocket');

let port = 3008

// 用户列表 根据用户名索引
const clients = new Map() 

// 根据clientSocket索引用户名
const clientsName = new Map()

// 房间列表 根据房主名索引
const games = new Map()

// 消息类型
const register = 0
const create   = 1
const join     = 2
const move     = 3
const over     = 4
const quit     = 5

// 状态类型
const success  = 0
const error    = 1

// 执棋颜色
const none  = 0
const black = 1
const white = 2


// 创建一个游戏房间
function newGame(p1){
    return {
        player1 : p1,
        player2 : "",
        vacant  : true,
        color   : black,
        chessboard : newChessboard()
    }
}

// 创建新的用户对象
function newClient(uname, cli, col){
    return {
        username : uname,
        socket   : cli,
        color    : col,           
    }
}

// 返回一个空棋盘
function newChessboard(){
    // 记录棋盘内容
    let chessboard = []
    for(let i=0; i<10; ++i){
        chessboard.push([0,0,0,0,0,0,0,0,0,0])
    }
    return chessboard
}

// 检测某一个棋子是否获胜 仅在落子处检查
function check(chessboard, color, row, col){
    // 所在行检查
    let count = 0
    for(let j=0; j<10; ++j){
        if(chessboard[row][j] == color && ++count >= 5)     return true
        else if(chessboard[row][j] != color)                count = 0
    }
    // console.log("no row")
    
    // 所在列检查
    count = 0
    for(let i=0; i<10; ++i){
        if(chessboard[i][col] == color && ++count >= 5)     return true
        else if(chessboard[i][col] != color)                count = 0
    }
    // console.log("no col")
    
    // 主对角线检查
    count = 0
    let i = row
    let j = col
    // 定位到最左上角
    while(i>0 && j>0){
        --i
        --j
    }
    while(i<10 && j<10){
        if(chessboard[i][j] == color && ++count >= 5)       return true
        else if(chessboard[i][j] != color)                  count = 0
        ++i
        ++j
    }
    // console.log("no main")

    // 副对角线检查
    count = 0
    i = row
    j = col
    // 定位到最右上角
    while(i>0 && j<10){
        --i
        ++j
    }
    while(i<10 && j>0){
        if(chessboard[i][j] == color && ++count >= 5)       return true
        else if(chessboard[i][j] != color)                  count = 0
        ++i
        --j
    }
    // console.log("no vice")

    return false
}




let server = ws.createServer(function(clientSocket){

    console.log('new connection');

    clientSocket.on("error", () => {
        // console.log("异常")
    })

    // 收到消息回应
    clientSocket.on("text", function(data){
        try{
            data = JSON.parse(data.toString())
        }
        catch(d){
            console.log("收到了无效信息: ")
            console.log(data)
            return
        }

        switch (data.type) {
            // 用户名注册 {type,username}
            case register:
                // 用户名重复 返回创建失败
                if(clients.has(data.username)){
                    console.log("用户"+data.username+"因用户名重复注册失败.")
                    clientSocket.sendText(JSON.stringify({type : register, state : error}))
                }
                else{
                    // 将用户添加至用户列表
                    clients.set(data.username, newClient(data.username, clientSocket, none))
                    clientsName.set(clientSocket, data.username)

                    // 告知用户注册成功
                    clientSocket.sendText(JSON.stringify({type : register, state : success}))

                    console.log("用户"+data.username+"完成了注册")
                }
                console.log()
                break

            // 创建房间{type, username}
            case create:
                // 如果用户已经注册 创建成功提示
                if(clients.has(data.username)){
                    // 允许同一玩家重复创建房间 但是会覆盖之前的房间
                    // 创建房间
                    games.set(data.username, newGame(data.username))

                    // 告知玩家房间创建成功
                    clientSocket.sendText(JSON.stringify({type : create, state : success}))

                    console.log("用户"+data.username+"创建了房间")
                }
                // 用户未注册
                else{
                    console.log("用户"+data.username+"因为未注册，创建房间失败")
                    clientSocket.sendText(JSON.stringify({type : create, state : error}))
                }
                console.log()
                break

            // 加入房间 {type, username, hostname}    
            case join:          
                // 必须玩家已经注册且对应房间存在
                if(clients.has(data.username) && games.has(data.hostname)){
                    // 对手已经创建房间且在等待
                    if(games.get(data.hostname).vacant){
                        // TODO 高并发要加锁
                        // 更新房间待命信息 此时房间不可再加入
                        games.get(data.hostname).vacant = false

                        // 更新房间的对局信息 加入者作为p2
                        games.get(data.hostname).player2 = data.username
                        
                        // 更新两位玩家的执棋颜色
                        clients.get(data.username).color = white
                        clients.get(data.hostname).color = black
                        
                        // 更新游戏棋盘
                        games.get(data.hostname).chessboard = newChessboard()

                        // 告知玩家2 房间加入成功
                        clientSocket.sendText(JSON.stringify({type:join, state:success, opponent:data.hostname}))
                        
                        // 告知房主 玩家2已加入房间
                        clients.get(data.hostname).socket.sendText(JSON.stringify({type : join, state : success, opponent:data.username}))
                        
                        console.log("用户"+data.username+"加入了"+data.hostname+"的房间")
                    }
                    // 失败
                    else{
                        console.log("用户"+data.username+"加入"+data.opponent+"的房间失败，因为游戏已经开始")
                        clientSocket.sendText(JSON.stringify({type : join, state : error}))
                    }
                }
                else{
                    console.log("用户"+data.username+"加入"+data.opponent+"的房间失败，因为用户或房间不存在")
                    clientSocket.sendText(JSON.stringify({type : join, state : error}))
                }
                console.log()
                break

            // 落子 {type, hostname, color, row, col}
            case move:
                if(games.has(data.hostname)){
                    let game = games.get(data.hostname)
                    // 是正确的人落子 且落子处此前无子
                    if(game.color == data.color && game.chessboard[data.row][data.col] == none){
                        //  修改棋盘状态和执棋顺序
                        game.chessboard[data.row][data.col] = data.color
                        game.color = (data.color == white) ? black : white

                        // 向双方同步落子信息
                        clients.get(game.player1).socket.sendText(JSON.stringify({type:move, row:data.row, col:data.col, color:data.color, state:success}))
                        clients.get(game.player2).socket.sendText(JSON.stringify({type:move, row:data.row, col:data.col, color:data.color, state:success}))
                        
                        let cur_player = data.color == black ? game.player1 : game.player2 
                        console.log(cur_player+"落子于: "+data.row+ " "+data.col)

                        
                        // 检查是否有人获胜
                        if(check(game.chessboard, data.color ,data.row, data.col)){
                            // 给两位玩家发送游戏结束信息
                            clients.get(game.player1).socket.sendText(JSON.stringify({type:over, winner:cur_player}))
                            clients.get(game.player2).socket.sendText(JSON.stringify({type:over, winner:cur_player}))
                            // console.log(game.chessboard)
                            console.log(cur_player+"玩家胜利！")
                        }
                    }
                    else{
                        console.log("不是正确的人落子")
                        console.log(data)
                    }
                }
                else{
                    console.log("move：房间不存在")
                    console.log(data)
                }
                console.log()
                break

            // 玩家退出 {type, username}
            case quit:
                if(clients.has(data.username)){
                    // 删除用户数据
                    clients.delete(data.username)
                    // 删除游戏信息
                    if(games.has(data.username)){
                        games.delete(data.username)
                    }
                    console.log("用户："+ data.username + "已退出")
                }


            // 无效信息
            default:
                console.log("收到了无效信息: ")
                console.log(data)
                break
        }        
    })

    // 断开连接触发
    clientSocket.on("close",function(){
        // 删除对应的用户及游戏
        clients.delete(clientsName.get(clientSocket))
        games.delete(clientsName.get(clientSocket))
        console.log("用户"+clientsName.get(clientSocket)+"已退出")
        clientsName.delete(clientSocket)
    })


}).listen(port)


console.log("websocket server listen port is " + port)